//
//  RSBiometryAuth.m
//  RSTools
//
//  Created by thinkjoy on 2017/10/12.
//  Copyright © 2017年 杜瑞胜. All rights reserved.
//  WJTouchID https://github.com/bringbird/WJTouchID
//  http://blog.csdn.net/loser_loser1/article/details/71107573

#import "RSBiometryAuth.h"

#define RSNotice(Chinese,English) [[[[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"] objectAtIndex:0] containsString:@"zh-Hans"] ? Chinese : English

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

@implementation RSBiometryAuth

+ (instancetype)sharedApplication
{
    static RSBiometryAuth * _biometryAuth;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _biometryAuth   =   [[RSBiometryAuth alloc] init];
    });
    return _biometryAuth;
}

- (void)startRSBiometryAuthWithMessage:(NSString *)message fallbackTitle:(NSString *)fallbackTitle policy:(LAPolicy)policy delegate:(id<RSBiometryAuthDelegate>)delegate
{
    NSAssert(delegate != nil, RSNotice(@"RSBiometryAuthDelegate 不能为空", @"RSBiometryAuthDelegate must be non-nil"));
    
    LAContext *context = [[LAContext alloc]init];
    context.localizedFallbackTitle = fallbackTitle;
    NSError *error = nil;
    self.delegate = delegate;
    
    //    context.localizedCancelTitle   iOS10 以后增加，默认为“取消”
    
    /**
     context.evaluatedPolicyDomainState iOS9 以后增加，
     
     此属性仅在调用评估策略和成功的Touch ID身份验证时设置，或者当canEvaluatePolicy成功执行生物识别策略时。
     它在所有其他情况下都是空的。
     如果手指数据库修改(手指被添加或删除),evaluatedPolicyDomainState数据将会改变。自然这样的数据库更改不能确定但是比较不同evaluatePolicy evaluatedPolicyDomainState后的数据将揭示事实数据库调用之间的变化。
     请注意，此属性返回的值也可以在OS版本之间更改，即使没有更改注册的指纹。
     */
    
    /**
     touchIDAuthenticationAllowableReuseDuration iOS9 以后增加
     
     接受一个成功的Touch ID设备的时间间隔(在锁屏上)。
     这个属性可以在秒内设置一个时间间隔。如果该设备在这个时间间隔内通过Touch ID成功解锁，那么在此上下文中触摸ID身份验证将自动成功，并在不提示用户使用Touch ID的情况下调用应答块。
     默认值为0，这意味着之前没有任何TouchID解锁可以被重用。
     他的属性仅用于从设备锁屏幕中重新使用Touch ID匹配。
     它不允许在应用程序或应用程序之间重用以前的Touch ID匹配。
     最大支持时间间隔为5分钟，设置超过5分钟的值并不会增加被接受的时间间隔。
     
     这个属性应该是类似于支付宝的指纹开启应用，如果你打开他解锁之后，按Home键返回桌面，再次进入支付宝是不需要录入指纹的。因为这个属性可以设置一个时间间隔，在时间间隔内是不需要再次录入。默认是0秒，最长可以设置5分钟。
     */
    if (SYSTEM_VERSION_LESS_THAN(@"9")) {//低于iOS9
        policy  =   kLAPolicyDeviceOwnerAuthenticationWithBiometrics;
    }
    
    if ([context canEvaluatePolicy:policy error:&error]) {
        NSLog(@"context.evaluatedPolicyDomainState=%@",context.evaluatedPolicyDomainState);
        
        [context evaluatePolicy:policy localizedReason:message == nil ? RSNotice(@"自定义信息", @"The Custom Message") : message reply:^(BOOL success, NSError * _Nullable error) {
            
            if (success) {
                if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeSuccess)]) {
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        [self.delegate RSBiometryAuthAuthorizeSuccess];
                    }];
                }
            } else if (error) {
                
                switch (error.code) {
                        
                    case LAErrorAuthenticationFailed: { // -1 连续三次指纹识别错误
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeFailure)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeFailure];
                            }];
                        }
                    }
                        break;
                        
                    case LAErrorUserCancel: {   //-2 在TouchID对话框中点击了取消按钮
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorUserCancel)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorUserCancel];
                            }];
                        }
                    }
                        break;
                        
                    case LAErrorUserFallback: { //-3 在TouchID对话框中点击了输入密码按钮
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorUserFallback)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorUserFallback];
                            }];
                        }
                    }
                        break;
                        
                    case LAErrorSystemCancel:{  // -4 TouchID对话框被系统取消，例如按下Home或者电源键
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorSystemCancel)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorSystemCancel];
                            }];
                        }
                    }
                        break;
                        
                    case LAErrorPasscodeNotSet: {   //-5 设备系统未设置密码
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorPasscodeNotSet)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorPasscodeNotSet];
                            }];
                        }
                    }
                        break;
                        
                        /**
                             LAErrorTouchIDNotAvailable 设备未设置Touch ID,>=iOS8 && <iOS11
                             LAErrorBiometryNotAvailable    设备未设置Biometry,>=iOS11
                         */
                    case -6: {
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorBiometryNotAvailable)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorBiometryNotAvailable];
                            }];
                        }
                    }
                        break;
                        
                        /**
                         LAErrorTouchIDNotEnrolled 用户未录入指纹,>=iOS8 && <iOS11
                         LAErrorBiometryNotEnrolled    用户未录入Biometry,>=iOS11
                         */
                    case -7: {
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorBiometryNotEnrolled)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorBiometryNotEnrolled];
                            }];
                        }
                    }
                        break;
                        
                        /**
                         LAErrorTouchIDLockout 连续五次指纹识别错误，TouchID功能被锁定，下一次需要输入系统密码,>=iOS8 && <iOS11
                         LAErrorBiometryLockout    连续五次指纹识别错误，Biometry功能被锁定，下一次需要输入系统密码,>=iOS11
                         */
                    case -8: {
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorBiometryLockout)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorBiometryLockout];
                            }];
                        }
                    }
                        break;
                        
                    case LAErrorAppCancel:  {   //-9,用户不能控制情况下APP被挂起,如突然来了电话，电话应用进入前台，APP被挂起啦
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorAppCancel)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorAppCancel];
                            }];
                        }
                    }
                        break;
                        
                    case LAErrorInvalidContext: {   //-10,LAContext传递给这个调用之前已经失效
                        
                        if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorInvalidContext)]) {
                            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                                [self.delegate RSBiometryAuthAuthorizeErrorInvalidContext];
                            }];
                        }
                    }
                        break;
                }
            }
        }];
        
    } else {
        /**
         LAErrorTouchIDLockout 连续五次指纹识别错误，TouchID功能被锁定，下一次需要输入系统密码,>=iOS8 && <iOS11
         LAErrorBiometryLockout    连续五次指纹识别错误，Biometry功能被锁定，下一次需要输入系统密码,>=iOS11
         */
        if (error.code == -8) {
            if ([self.delegate respondsToSelector:@selector(RSBiometryAuthAuthorizeErrorBiometryLockout)]) {
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    [self.delegate RSBiometryAuthAuthorizeErrorBiometryLockout];
                }];
            }
        }else{
            if ([self.delegate respondsToSelector:@selector(RSBiometryAuthIsNotSupport)]) {
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    [self.delegate RSBiometryAuthIsNotSupport];
                }];
            }
        }
        
    }
}

/*
 typedef NS_ENUM(NSInteger, LAError)
 {
 //授权失败
 LAErrorAuthenticationFailed = kLAErrorAuthenticationFailed,
 
 //用户取消Touch ID授权
 LAErrorUserCancel           = kLAErrorUserCancel,
 
 //用户选择输入密码
 LAErrorUserFallback         = kLAErrorUserFallback,
 
 //系统取消授权(例如其他APP切入)
 LAErrorSystemCancel         = kLAErrorSystemCancel,
 
 //系统未设置密码
 LAErrorPasscodeNotSet       = kLAErrorPasscodeNotSet,
 
 //设备Touch ID不可用，例如未打开
 LAErrorTouchIDNotAvailable  = kLAErrorTouchIDNotAvailable,
 
 //设备Touch ID不可用，用户未录入
 LAErrorTouchIDNotEnrolled   = kLAErrorTouchIDNotEnrolled,
 } NS_ENUM_AVAILABLE(10_10, 8_0);
 
 LAErrorTouchIDLockout   NS_ENUM_AVAILABLE(10_11, 9_0) = kLAErrorTouchIDLockout,
 
 LAErrorAppCancel        NS_ENUM_AVAILABLE(10_11, 9_0) = kLAErrorAppCancel,
 
 LAErrorInvalidContext   NS_ENUM_AVAILABLE(10_11, 9_0) = kLAErrorInvalidContext
 
 其中，LAErrorTouchIDLockout是在8.0中也会出现的情况，但并未归为单独的错误类型，这个错误出现，源自用户多次连续使用Touch ID失败，Touch ID被锁，需要用户输入密码解锁，这个错误的交互LocalAuthentication.framework已经封装好了，不需要开发者关心。
 
 LAErrorAppCancel和LAErrorSystemCancel相似，都是当前软件被挂起取消了授权，但是前者是用户不能控制的挂起，例如突然来了电话，电话应用进入前台，APP被挂起。后者是用户自己切到了别的应用，例如按home键挂起。
 
 LAErrorInvalidContext很好理解，就是授权过程中,LAContext对象被释放掉了，造成的授权失败。
 
 */

@end
